"""训练服务"""
from app.ai.recommendation_service import get_recommendation_service
from app.ai.llm_service import get_llm_service
from app.core.database import RedisClient
from typing import Dict, Any, List, Optional
from datetime import datetime
import uuid
import json


class TrainingService:
    """训练服务类"""
    
    def __init__(self):
        self.recommendation_service = get_recommendation_service()
        self.llm_service = get_llm_service()
        try:
            self.redis = RedisClient.get_client()
            # 测试连接
            self.redis.ping()
        except Exception as e:
            print(f"警告: Redis连接失败，将使用内存存储: {e}")
            self.redis = None
            self._memory_storage = {}  # 内存存储作为后备
        
        # 初始化每日记录存储（即使Redis可用也保留，作为备份）
        self._daily_records = {}
        self._daily_completed = {}
    
    async def create_session(
        self,
        user_id: str,
        plan_id: Optional[str] = None
    ) -> Dict[str, Any]:
        """创建训练会话"""
        session_id = f"session_{uuid.uuid4().hex[:8]}"
        return {
            "session_id": session_id,
            "user_id": user_id,
            "plan_id": plan_id,
            "status": "active",
            "started_at": datetime.now().isoformat()
        }
    
    async def get_next_question(
        self,
        session_id: str,
        user_id: str
    ) -> Dict[str, Any]:
        """获取下一个题目（从题库中按权重推荐，排除已做过的题目）"""
        from app.ai.question_generator import question_generator
        from app.db.question_bank import get_question_by_id
        
        # 获取当前会话中已做过的题目ID列表
        answered_question_ids = []
        if self.redis:
            try:
                session_questions_key = f"session_questions:{session_id}"
                if self.redis.exists(session_questions_key):
                    answered_set = self.redis.smembers(session_questions_key) or set()
                    answered_question_ids = [
                        qid.decode('utf-8') if isinstance(qid, bytes) else qid 
                        for qid in answered_set
                    ]
            except Exception as e:
                print(f"Redis操作失败，使用内存存储: {e}")
                self.redis = None
                self._memory_storage = {}
        
        # 如果Redis不可用，使用内存存储
        if not self.redis:
            if session_id not in self._memory_storage:
                self._memory_storage[session_id] = set()
            answered_question_ids = list(self._memory_storage[session_id])
        
        # 使用题目生成器按权重推荐题目，排除已做过的
        question_ids = await question_generator.recommend_questions(
            user_id, 
            count=10,  # 多推荐几个，避免重复
            exclude_question_ids=answered_question_ids
        )
        
        # 从推荐列表中过滤掉已做过的题目
        available_question_ids = [
            qid for qid in question_ids 
            if qid not in answered_question_ids
        ]
        
        # 如果所有推荐的题目都做过了，尝试获取更多题目
        if not available_question_ids:
            # 获取更多题目，排除已做过的
            more_question_ids = await question_generator.recommend_questions(
                user_id,
                count=50,  # 扩大范围
                exclude_question_ids=answered_question_ids
            )
            available_question_ids = [
                qid for qid in more_question_ids 
                if qid not in answered_question_ids
            ]
        
        # 如果还是没有可用题目，说明题库题目都做完了
        if not available_question_ids:
            # 返回提示信息
            return {
                "question_id": "no_more_questions",
                "session_id": session_id,
                "content": "恭喜！您已经完成了当前题库中的所有题目。",
                "options": [],
                "type": "info",
                "difficulty": "none",
                "knowledge_points": [],
                "is_completed": True
            }
        
        # 选择第一个可用题目
        question_id = available_question_ids[0]
        
        # 从题库中获取题目
        question_data = get_question_by_id(question_id)
        
        if question_data:
            # 自动修正题目类型：如果正确答案包含多个选项，自动按多选题处理
            question_type = question_data.get("type", "single_choice")
            correct_answer = question_data.get("correct_answer", "")
            
            # 检查正确答案是否包含多个选项
            import json
            import re
            def extract_options_count(answer_text: str) -> int:
                """从答案文本中提取选项数量"""
                if not answer_text:
                    return 0
                # 尝试解析JSON格式
                try:
                    if answer_text.strip().startswith('['):
                        data = json.loads(answer_text)
                        if isinstance(data, list):
                            return len(data)
                except:
                    pass
                # 提取"选项X"格式的所有选项
                matches = re.findall(r'选项([A-D])', answer_text)
                return len(set(matches))
            
            correct_options_count = extract_options_count(correct_answer)
            if correct_options_count > 1 and question_type == "single_choice":
                # 自动修正为多选题
                question_type = "indefinite_choice"
                print(f"⚠️ 题目 {question_id} 类型标记为单选，但正确答案包含 {correct_options_count} 个选项，自动修正为不定项选择题")
            
            return {
                "question_id": question_data.get("question_id"),
                "session_id": session_id,
                "content": question_data.get("content"),
                "options": question_data.get("options", []),
                "type": question_type,  # 使用修正后的类型
                "difficulty": question_data.get("difficulty", "medium"),
                "knowledge_points": question_data.get("knowledge_points", []),
                "category": question_data.get("category"),
                "subject": question_data.get("subject")
            }
        
        # 如果题库中没有，返回默认题目
        return {
            "question_id": question_id,
            "session_id": session_id,
            "content": "题目加载中...",
            "options": [],
            "type": "single_choice",
            "difficulty": "medium",
            "knowledge_points": []
        }
    
    async def submit_answer(
        self,
        session_id: str,
        question_id: str,
        user_answer: str,
        time_spent: float
    ) -> Dict[str, Any]:
        """提交答案并评估"""
        from app.db.question_bank import get_question_by_id
        
        # 从题库中获取正确答案
        question_data = get_question_by_id(question_id)
        
        if question_data:
            correct_answer = question_data.get("correct_answer", "选项C")
            explanation = question_data.get("explanation", "根据相关法律规定，该选项是正确的。")
            question_type = question_data.get("type", "single_choice")
            # 如果有LegalBERT增强的解释，可以合并
            bert_explanation = await self.llm_service.generate_explanation(
                question_data.get("content", ""),
                correct_answer
            )
            # 合并解释
            if "[模拟解释]" not in bert_explanation:
                explanation = f"{explanation}\n\n{bert_explanation}"
        else:
            # 默认题目
            correct_answer = "选项C"
            question_type = "single_choice"
            explanation = await self.llm_service.generate_explanation(
                "合同纠纷管辖问题",
                correct_answer
            )
        
        # 提取选项标识（支持单选和多选）
        import re
        import json
        
        def extract_options(answer_text: str) -> set:
            """从答案文本中提取所有选项标识"""
            if not answer_text:
                return set()
            
            options = set()
            
            # 尝试解析JSON格式（如：[{"id":"A","text":"..."},{"id":"C","text":"..."}]）
            try:
                if answer_text.strip().startswith('['):
                    data = json.loads(answer_text)
                    if isinstance(data, list):
                        for item in data:
                            if isinstance(item, dict):
                                option_id = item.get("id", "")
                                if option_id:
                                    options.add(f"选项{option_id}")
            except:
                pass
            
            # 提取"选项X"格式的所有选项（支持"选项A、选项C"格式）
            matches = re.findall(r'选项([A-D])', answer_text)
            for match in matches:
                options.add(f"选项{match}")
            
            return options
        
        # 判断是单选还是多选
        # 先检查正确答案格式，如果正确答案包含多个选项，自动按多选题处理
        correct_options_set = extract_options(correct_answer)
        has_multiple_correct_answers = len(correct_options_set) > 1
        
        # 如果正确答案有多个选项，但题目类型是单选，自动修正为多选题
        if has_multiple_correct_answers and question_type == "single_choice":
            print(f"⚠️ 题目 {question_id} 类型标记为单选，但正确答案包含多个选项，自动按多选题处理")
            is_multiple_choice = True
        else:
            is_multiple_choice = question_type in ["multiple_choice", "indefinite_choice"]
        
        # 答案判断结果
        is_correct = False
        is_partially_correct = False
        missing_options = []  # 缺少的选项
        extra_options = []  # 多余的选项
        
        if is_multiple_choice:
            # 多选题：比较选项集合
            user_options = extract_options(user_answer)
            correct_options = extract_options(correct_answer)
            
            if len(user_options) == 0:
                # 未选择任何选项
                is_correct = False
                missing_options = list(correct_options)
            elif user_options == correct_options:
                # 完全正确
                is_correct = True
            elif user_options.issubset(correct_options):
                # 部分正确：用户选择的都在正确答案内，但不全
                is_partially_correct = True
                is_correct = False
                missing_options = list(correct_options - user_options)
            else:
                # 有错误选项：用户选择了不在正确答案中的选项
                is_correct = False
                missing_options = list(correct_options - user_options)
                extra_options = list(user_options - correct_options)
        else:
            # 单选题：只比较第一个选项
            # 先从正确答案中提取选项（支持JSON格式和简单格式）
            correct_options_set = extract_options(correct_answer)
            user_options_set = extract_options(user_answer)
            
            # 单选题应该只有一个正确选项
            if len(correct_options_set) == 1 and len(user_options_set) == 1:
                # 比较选项集合
                is_correct = user_options_set == correct_options_set
                if not is_correct:
                    # 提取正确选项的ID（去掉"选项"前缀）
                    correct_option_id = list(correct_options_set)[0].replace("选项", "")
                    missing_options = [correct_option_id]
            else:
                # 兼容旧逻辑：使用正则表达式提取
                user_option_match = re.search(r'选项([A-D])', user_answer) if user_answer else None
                correct_option_match = re.search(r'选项([A-D])', correct_answer) if correct_answer else None
                is_correct = (
                    user_option_match and correct_option_match and 
                    user_option_match.group(1) == correct_option_match.group(1)
                )
                if not is_correct and correct_option_match:
                    missing_options = [correct_option_match.group(1)]
        
        # 处理部分正确的情况
        partial_correct_feedback = None
        unmastered_knowledge_points = []
        
        if is_partially_correct:
            # 分析缺少选项对应的知识点
            all_knowledge_points = question_data.get("knowledge_points", []) if question_data else []
            if missing_options and all_knowledge_points:
                # 计算缺少的比例
                missing_ratio = len(missing_options) / len(correct_options) if correct_options else 0
                # 标记相应比例的知识点为未掌握
                num_missing_kp = max(1, int(len(all_knowledge_points) * missing_ratio))
                unmastered_knowledge_points = all_knowledge_points[:num_missing_kp]
            elif missing_options:
                unmastered_knowledge_points = [f"选项{opt.replace('选项', '')}相关知识点" for opt in missing_options]
            
            # 生成部分正确的批注
            missing_options_text = "、".join([opt.replace("选项", "选项") for opt in missing_options])
            partial_correct_feedback = {
                "is_partial": True,
                "message": f"您的答案部分正确，但缺少了 {missing_options_text}。",
                "missing_options": missing_options,
                "missing_knowledge_points": unmastered_knowledge_points,
                "feedback": f"您已掌握了部分知识点，但还需要加强对以下知识点的理解：{', '.join(unmastered_knowledge_points) if unmastered_knowledge_points else '相关知识点'}。"
            }
        elif not is_correct and question_data:
            # 完全错误时，标记所有知识点为未掌握
            unmastered_knowledge_points = question_data.get("knowledge_points", [])
        
        # 详细的分析（包括做题思路、正确答案解释）
        # 答对时：分析为什么正确，巩固正确思路
        # 答错时：分析错误原因，指出问题
        detailed_analysis = None
        
        if is_correct and question_data:
            # 答对时，使用大模型分析为什么正确，巩固正确思路
            try:
                from app.ai.evaluation_engine import get_evaluation_engine
                import asyncio
                evaluation_engine = get_evaluation_engine()
                detailed_analysis = await asyncio.wait_for(
                    evaluation_engine.generate_correct_answer_analysis(
                        question_content=question_data.get("content", ""),
                        question_options=question_data.get("options", []),
                        user_answer=user_answer,
                        correct_answer=correct_answer,
                        explanation=explanation,
                        knowledge_points=question_data.get("knowledge_points", [])
                    ),
                    timeout=60.0  # 60秒超时，给大模型充足时间
                )
            except asyncio.TimeoutError:
                print("生成正确答案分析超时（60秒）")
                detailed_analysis = None
            except Exception as e:
                print(f"生成正确答案分析失败: {e}")
                detailed_analysis = None
        
        # 详细的错误分析（包括做题思路、正确答案解释、错误点分析）
        detailed_error_analysis = None
        if not is_correct and question_data:
            try:
                import asyncio
                from app.ai.evaluation_engine import get_evaluation_engine
                evaluation_engine = get_evaluation_engine()
                detailed_error_analysis = await asyncio.wait_for(
                    evaluation_engine.generate_detailed_error_analysis(
                        question_content=question_data.get("content", ""),
                        question_options=question_data.get("options", []),
                        user_answer=user_answer,
                        correct_answer=correct_answer,
                        explanation=explanation,
                        knowledge_points=question_data.get("knowledge_points", [])
                    ),
                    timeout=60.0  # 60秒超时，给大模型充足时间
                )
            except asyncio.TimeoutError:
                print("生成详细错误分析超时（60秒），使用基础分析")
                detailed_error_analysis = None
            except Exception as e:
                print(f"生成详细错误分析失败: {e}")
                detailed_error_analysis = None
        
        # 从session_id提取user_id
        user_id = session_id.split('_')[1] if '_' in session_id else "user_001"
        
        # 记录已做过的题目（添加到会话题目集合中）
        if self.redis:
            try:
                session_questions_key = f"session_questions:{session_id}"
                self.redis.sadd(session_questions_key, question_id)
                self.redis.expire(session_questions_key, 86400 * 7)  # 7天后过期
            except Exception as e:
                print(f"Redis操作失败: {e}")
        else:
            # 使用内存存储
            if session_id not in self._memory_storage:
                self._memory_storage[session_id] = set()
            self._memory_storage[session_id].add(question_id)
        
        # 保存到每日学习记录（供进度监控使用）
        today = datetime.now().strftime('%Y-%m-%d')
        record_data = {
            "question_id": question_id,
            "user_answer": user_answer,
            "correct_answer": correct_answer,
            "is_correct": is_correct,
            "time_spent": time_spent,
            "timestamp": datetime.now().isoformat(),
            "session_id": session_id,
            "source": "training"  # 标记来源是训练工作台
        }
        
        # 保存到Redis（如果可用）
        if self.redis:
            try:
                # 保存到每日记录
                record_key = f"daily_record:{user_id}:{today}"
                self.redis.hset(record_key, question_id, json.dumps(record_data, ensure_ascii=False))
                self.redis.expire(record_key, 86400 * 365)  # 保存1年
                
                # 同时记录到已完成题目集合
                completed_key = f"daily_completed:{user_id}:{today}"
                self.redis.sadd(completed_key, question_id)
                self.redis.expire(completed_key, 86400 * 365)
            except Exception as e:
                print(f"保存每日记录到Redis失败: {e}")
        
        # 无论Redis是否可用，都保存到内存存储（供进度服务读取）
        record_key = f"{user_id}:{today}"
        if record_key not in self._daily_records:
            self._daily_records[record_key] = {}
        self._daily_records[record_key][question_id] = record_data
        
        completed_key = f"{user_id}:{today}"
        if completed_key not in self._daily_completed:
            self._daily_completed[completed_key] = set()
        self._daily_completed[completed_key].add(question_id)
        
        # 更新题目的做错/做对次数（与daily_learning_service保持一致）
        if question_data:
            question_data["wrong_count"] = question_data.get("wrong_count", 0)
            question_data["correct_count"] = question_data.get("correct_count", 0)
            
            if not is_correct:
                question_data["wrong_count"] += 1
            else:
                question_data["correct_count"] += 1
        
        # 更新难度评估
        from app.services.difficulty_service import difficulty_service
        difficulty_service.update_question_difficulty(question_id, is_correct)
        
        # 更新用户水平
        from app.services.user_level_service import user_level_service
        user_level_service.update_user_level(user_id, question_id, is_correct)
        
        # 更新用户偏好
        await self.recommendation_service.update_user_preferences(
            user_id,
            question_id,
            is_correct,
            time_spent
        )
        
        # 格式化正确答案用于显示（将JSON格式转换为可读文本）
        def format_answer_for_display(answer_text: str) -> str:
            """将答案格式化为可读文本"""
            if not answer_text:
                return ""
            
            # 尝试解析JSON格式
            try:
                if answer_text.strip().startswith('['):
                    data = json.loads(answer_text)
                    if isinstance(data, list):
                        # 提取所有选项ID并排序
                        option_ids = []
                        for item in data:
                            if isinstance(item, dict):
                                option_id = item.get("id", "")
                                if option_id:
                                    option_ids.append(option_id)
                        if option_ids:
                            # 按字母顺序排序，然后用"、"连接
                            option_ids.sort()
                            return "、".join([f"选项{id}" for id in option_ids])
            except:
                pass
            
            # 如果不是JSON格式，直接返回原文本
            return answer_text
        
        formatted_correct_answer = format_answer_for_display(correct_answer)
        
        return {
            "session_id": session_id,
            "question_id": question_id,
            "is_correct": is_correct,
            "is_partially_correct": is_partially_correct,  # 部分正确标识
            "user_answer": user_answer,
            "correct_answer": formatted_correct_answer,
            "explanation": explanation,
            "partial_correct_feedback": partial_correct_feedback,  # 部分正确的批注
            "detailed_error_analysis": detailed_error_analysis,  # 详细的错误分析（包括做题思路、正确答案解释、错误点分析）
            "detailed_analysis": detailed_analysis if is_correct else detailed_error_analysis,  # 详细分析（答对时：为什么正确；答错时：错误分析）
            "unmastered_knowledge_points": unmastered_knowledge_points,  # 未掌握的知识点
            "missing_options": missing_options,  # 缺少的选项
            "extra_options": extra_options,  # 多余的选项
            "score": 10 if is_correct else (5 if is_partially_correct else 0),  # 部分正确给5分
            "time_spent": time_spent
        }


training_service = TrainingService()

